#include "OccupancySensor.h"

#include "Tools.h"

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

using namespace app::Clusters;
using namespace app::Clusters::OccupancySensing::Attributes;

namespace {
// Declare Occupancy cluster attributes
constexpr DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(occupancyAttrs)
    DECLARE_DYNAMIC_ATTRIBUTE(Occupancy::Id, BITMAP8, 1, 0),
    DECLARE_DYNAMIC_ATTRIBUTE(OccupancySensorType::Id, ENUM8, 1, 0),
    DECLARE_DYNAMIC_ATTRIBUTE(OccupancySensorTypeBitmap::Id, BITMAP8, 1, 0),
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

EmberAfCluster occupancySensorCluster = DECLARE_DYNAMIC_CLUSTER(
    OccupancySensing::Id,
    occupancyAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr);
}

OccupancySensor::OccupancySensor(const ::BasicInformation* node)
    : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "OccupancySensor");
    mClusters.push_back(occupancySensorCluster);
    mMeasurement = 0x00;
}

void OccupancySensor::SetMeasuredValue(uint8_t measurement) {
    const bool changed = mMeasurement != measurement;
    mMeasurement = measurement;
    ChipLogProgress(DeviceLayer, "Device[%s] new measurement=\"%d\"",
                    GetName().c_str(), measurement);
    if (changed) {
        NotifyStatusChanged(OccupancySensing::Id, Occupancy::Id);
    }
}

Protocols::InteractionModel::Status OccupancySensor::ReadAttribute(
    ClusterId clusterId,
    AttributeId attributeId,
    uint8_t* buffer,
    uint16_t maxReadLength) {
    if (clusterId != OccupancySensing::Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }
    ChipLogProgress(DeviceLayer, "ReadAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);

    if (attributeId == Occupancy::Id) {
        tools::GetAttr(buffer, maxReadLength, GetMeasuredValue());
    } else if (attributeId == OccupancySensorType::Id) {
        tools::GetAttr(buffer, maxReadLength, static_cast<uint8_t>(0x00));
    } else if (attributeId == OccupancySensorTypeBitmap::Id) {
        tools::GetAttr(buffer, maxReadLength, static_cast<uint8_t>(0x00));
    } else {
        return Protocols::InteractionModel::Status::UnsupportedRead;
    }
    return Protocols::InteractionModel::Status::Success;
}

ChipError OccupancySensor::OnReport(const DataBlock* block) {
    if (block->path.clusterId != OccupancySensing::Id) {
        return BridgedDevice::OnReport(block);
    }

    if (block->path.attributeId == Occupancy::Id) {
        SetMeasuredValue(static_cast<uint8_t>(block->data.asInt()));
    }
    return CHIP_NO_ERROR;
}
